#include <stdio.h>
#include <string.h>
#include <time.h>
#include <stdlib.h>
#include <conio.h>
#include "Data.h"


void
GenRandBinVect(
		INT32* InputVector,
		INT32  Size,
		FILE*  RandVectxt
		)
{
	INT32 n = 0;
	srand( time(NULL) );

	for(n = 0 ; n < Size; n++)
	{
		InputVector[n] = rand() % 2;
		fprintf(RandVectxt, "%d", InputVector[n]);
	}
}

UINT32
CalculateErrorsNo(
		INT32*  InputVector,
		UINT8*  DecodedVector,
		UINT32  BitsNo
		)
{
	UINT16	idx 	  = 0;
	UINT32	ErrorsNo = 0;

	for(idx = 0; idx < BitsNo; idx++)
	{
		if( (UINT8)InputVector[idx] != DecodedVector[idx])
		{
			ErrorsNo++;
		}
	}
	return ErrorsNo;
}

DOUBLE
CalculateBer(UINT32 ErrorsNo,
			 UINT32 BitsNo,
			 UINT32 FrameNo)
{
	DOUBLE  Ber = 0.0;
	UINT32 SummaryBitsNo = 0;

	SummaryBitsNo = BitsNo * FrameNo;

	Ber = (DOUBLE)ErrorsNo / SummaryBitsNo;

	return Ber;
}

INT32
main(
	INT32  argc,
	CHAR8 *argv[]
	)
{
	static INT32	Register[REGISTER_CELL_NO]				= {0};
	static INT32 	RandInputVector[MAX_RANDOM_VECTOR]		= {0};
	INT32		 	InputVector[MAX_FRAME]					= {0};
	INT32 			CodedVector[MAX_FRAME] 					= {0};
	FLOAT 			OutputVector[MAX_FRAME]					= {0};
	UINT8			DecodedVector[MAX_FRAME]				= {0};
		
	UINT32			BitsNo	  = 0;
	UINT32			FrameNo   = 0;
	FLOAT			Step	  = 0.0;
	FLOAT			UpperEbNo = 0.0;
	FLOAT			LowerEbNo = 0.0;

	UINT32			i 				 = 0;
	UINT32			FrameCount 		 = 0;
	UINT32			RandInVectOffset = 0;
	UINT32			ErrorsNo		 = 0;
	DOUBLE			Ber				 = 0.0;

	FILE*			RandVectTxt 	= NULL;
	FILE*			CodedVectTxt    = NULL;
	FILE*			BerEbNoTxt		= NULL;

	printf("Frames Number: ");
	scanf("%d", &FrameNo);
	printf("Bits Number: ");
	scanf("%d", &BitsNo);
	printf("Upper Signal/Noise Ratio: ");
	scanf("%f", &UpperEbNo);
	printf("Lower Signal/Noise Ratio: ");
	scanf("%f", &LowerEbNo);
	printf("Step: ");
	scanf("%f", &Step);

	RandVectTxt		= fopen("RandVect.txt", "w");
	CodedVectTxt 	= fopen("CodedVect.txt", "w");
	BerEbNoTxt	 	= fopen("BerEbNo.txt", "w");

	GenRandBinVect(RandInputVector, MAX_RANDOM_VECTOR, RandVectTxt);

	printf("\nRunning");
	for( ; UpperEbNo >= LowerEbNo; UpperEbNo -= Step)
	{
		printf(".");
		for(RandInVectOffset = 0, ErrorsNo = 0, FrameCount = 0 ; FrameCount < FrameNo ; FrameCount++)
		{

			memset(Register, 0, sizeof(Register));
			memset(InputVector, 0, sizeof(InputVector));
			memset(CodedVector, 0, sizeof(CodedVector));
			memset(OutputVector, 0, sizeof(OutputVector));
			memcpy(InputVector, &RandInputVector[RandInVectOffset], sizeof(InputVector[0]) * BitsNo );

			Coder(InputVector,
				  Register,
				  CodedVector,
				  BitsNo
				  );

			for(i = 0 ; i < (CODED_FRAME_SIZE); i++)
			{
				fprintf(CodedVectTxt, "%d", CodedVector[i]);
			}

			Channel(UpperEbNo, (CODED_FRAME_SIZE) , CodedVector, OutputVector);

			RandInVectOffset += BitsNo;

			ViterbiDecoder(OutputVector,
						   DecodedVector,
						   CODED_FRAME_SIZE);

			ErrorsNo  += CalculateErrorsNo(InputVector,
						 	  	  	  	   DecodedVector,
						 	  	  	  	   BitsNo
						 	  	  	  	   );
		}
		Ber = CalculateBer(ErrorsNo,
					 	   FrameNo,
					 	   BitsNo);
		fprintf(BerEbNoTxt, "%lf	%lf\n", UpperEbNo, Ber * 100.0);
	}
	fclose(RandVectTxt);
	fclose(CodedVectTxt);
	fclose(BerEbNoTxt);

	return 0;	
}
